import { FastMCP } from "fastmcp";
import { z } from "zod";
import { CodeIndexOrchestrator } from "./services/orchestrator.js";
import { EmbedderFactory } from "./services/embedder-factory.js";
import { QdrantVectorStore } from "./vector-store/qdrant-client.js";
import { simpleCodeParser } from "./processors/simple-parser.js";
import { CacheManager } from "./services/cache-manager.js";
import { envConfig, validateEmbedderConfig, getVectorStoreConfig } from "./config/env-config.js";
import { parseShellCommand, mapShellCommandToTool, convertArgsToToolParams } from "./utils/shell-command-parser.js";

// Import tool schemas and implementations
import { indexCodebaseSchema, indexCodebaseTool } from "./tools/index-codebase.js";
import { searchCodeSchema, searchCodeTool } from "./tools/search-code.js";
import { getIndexStatusSchema, getIndexStatusTool } from "./tools/get-index-status.js";
import { clearIndexSchema, clearIndexTool } from "./tools/clear-index.js";

/**
 * Creates and configures the MCP server
 */
export function createMCPServer(): FastMCP {
  const server = new FastMCP({
    name: "codebase-rag-mcp",
    version: "1.0.0",
  });

  // Global orchestrator instance (will be initialized when first tool is called)
  let orchestrator: CodeIndexOrchestrator | null = null;

  // Orchestrator components (created once, but workspace-specific instances created per workspace)
  let globalComponents: {
    embedder: any;
    vectorStoreConfig: any;
    vectorDimensions: { code: number; text: number };
  } | null = null;

  // Workspace-specific orchestrators
  const orchestrators = new Map<string, CodeIndexOrchestrator>();

  /**
   * Initialize global components (embedder, configs)
   */
  async function initializeGlobalComponents() {
    if (!globalComponents) {
      console.log("Initializing global components...");
      
      // Validate embedder configuration
      const embeddingValidation = validateEmbedderConfig();
      if (!embeddingValidation.valid) {
        throw new Error(`Embedder configuration error: ${embeddingValidation.error}`);
      }

      // Create embedder
      const embedder = EmbedderFactory.createEmbedder();
      console.log(`Using embedder: ${embedder.embedderInfo.name}`);

      // Test embedder configuration
      const embeddingTest = await embedder.validateConfiguration();
      if (!embeddingTest.valid) {
        throw new Error(`Embedder validation failed: ${embeddingTest.error}`);
      }

      // Get vector store configuration
      const vectorStoreConfig = getVectorStoreConfig();
      const vectorDimensions = EmbedderFactory.getVectorDimensions();
      
      globalComponents = {
        embedder,
        vectorStoreConfig,
        vectorDimensions
      };
      
      console.log("Global components initialized successfully");
    }
  }

  /**
   * Get or create workspace-specific orchestrator
   */
  async function getOrchestrator(workspacePath?: string): Promise<CodeIndexOrchestrator> {
    await initializeGlobalComponents();
    
    if (!globalComponents) {
      throw new Error("Failed to initialize global components");
    }

    // Use a default workspace if none provided (for status checks, etc.)
    const effectiveWorkspace = workspacePath || "/tmp/mcp-default-workspace";
    
    let orch = orchestrators.get(effectiveWorkspace);
    if (!orch) {
      console.log(`Creating orchestrator for workspace: ${effectiveWorkspace}`);
      
      // Create workspace-specific vector store
      const vectorStore = new QdrantVectorStore(
        effectiveWorkspace,
        globalComponents.vectorStoreConfig.url,
        globalComponents.vectorDimensions,
        globalComponents.vectorStoreConfig.apiKey
      );

      // Create workspace-specific cache manager
      const cacheManager = new CacheManager(effectiveWorkspace);

      // Create orchestrator
      orch = new CodeIndexOrchestrator(
        globalComponents.embedder,
        vectorStore,
        simpleCodeParser,
        cacheManager
      );

      // Set up event handlers
      orch.on('statusChanged', (status) => {
        console.log(`[${effectiveWorkspace}] Index status changed: ${status.state} - ${status.message}`);
      });

      orch.on('error', (error) => {
        console.error(`[${effectiveWorkspace}] Orchestrator error:`, error);
      });

      orchestrators.set(effectiveWorkspace, orch);
      console.log(`Orchestrator created for workspace: ${effectiveWorkspace}`);
    }

    return orch;
  }

  // Keep track of the last indexed workspace for search operations
  let lastIndexedWorkspace: string | null = null;

  // Tool: Shell Command Interface
  server.addTool({
    name: "shell_command",
    description: "Execute codebase-rag-mcp commands using shell-like syntax. Supports: 'index <directory>', 'search <query>', 'status', 'clear', 'verify'. Examples: 'index /path/to/code', 'search --max-results 5 \"function definition\"', 'clear --confirm true'",
    parameters: z.object({
      command: z.string().describe("Shell command format (e.g., 'index /path/to/code', 'search \"query text\"', 'status', 'clear --confirm true')")
    }),
    execute: async (args) => {
      try {
        const parsed = parseShellCommand(args.command);
        if (!parsed) {
          return "❌ **Invalid Command Format**\n\nPlease use shell command format. Examples:\n- `index /path/to/code`\n- `search \"function definition\"`\n- `search --max-results 10 --min-score 0.8 \"query text\"`\n- `status`\n- `clear --confirm true`\n- `verify`";
        }

        const toolName = mapShellCommandToTool(parsed.command);
        if (!toolName) {
          return `❌ **Unknown Command: ${parsed.command}**\n\nSupported commands:\n- \`index\` - Index a codebase directory\n- \`search\` - Search indexed code\n- \`status\` - Get index status\n- \`clear\` - Clear index\n- \`verify\` - Verify configuration`;
        }

        const toolParams = convertArgsToToolParams(toolName, parsed.args);

        // Route to the appropriate tool
        switch (toolName) {
          case 'index_codebase':
            if (!toolParams.directory) {
              return "❌ **Missing Directory**\n\nUsage: `index <directory>`\nExample: `index /path/to/code`";
            }
            const indexOrch = await getOrchestrator(toolParams.directory);
            lastIndexedWorkspace = toolParams.directory;
            return await indexCodebaseTool(toolParams as { directory: string; verbose: boolean }, indexOrch);

          case 'search_code':
            if (!toolParams.query) {
              return "❌ **Missing Query**\n\nUsage: `search <query>`\nExample: `search \"function definition\"`\nWith options: `search --max-results 10 --rerank \"query text\"`";
            }
            if (!lastIndexedWorkspace) {
              return "❌ No codebase has been indexed yet. Please use `index <directory>` first.";
            }
            const searchOrch = await getOrchestrator(lastIndexedWorkspace);
            // Manually construct the arguments for searchCodeTool, including the new rerank flag
            const searchArgs = {
              query: toolParams.query as string,
              max_results: (toolParams.max_results as number) || 10,
              min_score: (toolParams.min_score as number) || 0.7,
              categorized_search: (toolParams.categorized_search as boolean) !== false,
              directory_prefix: toolParams.directory_prefix as string | undefined,
              text_min_score: toolParams.text_min_score as number | undefined,
              code_min_score: toolParams.code_min_score as number | undefined,
              rerank: (toolParams.rerank as boolean) || false,
            };
            return await searchCodeTool(searchArgs, searchOrch);

          case 'get_index_status':
            if (!lastIndexedWorkspace) {
              return "📊 **Code Index Status**\n\n**State:** ⏸️ STANDBY\n**Message:** No codebase has been indexed yet\n\n**Next Steps:**\n- Use `index <directory>` to start indexing";
            }
            const statusOrch = await getOrchestrator(lastIndexedWorkspace);
            return await getIndexStatusTool(toolParams as { verbose: boolean }, statusOrch);

          case 'clear_index':
            if (!lastIndexedWorkspace) {
              return "ℹ️ No codebase has been indexed yet. Nothing to clear.";
            }
            const clearOrch = await getOrchestrator(lastIndexedWorkspace);
            const result = await clearIndexTool(toolParams as { confirm: boolean }, clearOrch);
            if (result.includes("✅")) {
              lastIndexedWorkspace = null;
            }
            return result;

          case 'verify_configuration':
            // Re-use the existing verify configuration logic
            try {
              console.log("Verifying configuration...");
              
              const embeddingValidation = validateEmbedderConfig();
              if (!embeddingValidation.valid) {
                return `❌ **Embedder Configuration Error**\n\n${embeddingValidation.error}\n\nPlease check your .env file and ensure all required variables are set.`;
              }

              const embedder = EmbedderFactory.createEmbedder();
              const embeddingTest = await embedder.validateConfiguration();
              if (!embeddingTest.valid) {
                return `❌ **Embedder Connection Error**\n\n${embeddingTest.error}\n\nPlease verify your embedder service is running and credentials are correct.`;
              }

              const vectorStoreConfig = getVectorStoreConfig();
              const vectorDimensions = EmbedderFactory.getVectorDimensions();
              const vectorStore = new QdrantVectorStore(
                "/tmp/test",
                vectorStoreConfig.url,
                vectorDimensions,
                vectorStoreConfig.apiKey
              );
              await vectorStore.initialize();

              return `✅ **Configuration Verified Successfully**\n\n**Embedder:** ${embedder.embedderInfo.name}\n**Vector Database:** Connected to ${vectorStoreConfig.url}\n**Vector Dimensions:** Code: ${vectorDimensions.code}, Text: ${vectorDimensions.text}\n\nYour system is ready for codebase indexing and search!`;
            } catch (error) {
              const errorMessage = error instanceof Error ? error.message : String(error);
              return `❌ **Configuration Error**\n\n${errorMessage}\n\nPlease check your .env file and ensure all services are running.`;
            }

          default:
            return `❌ **Internal Error**: Unknown tool name: ${toolName}`;
        }
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return `❌ **Shell Command Error**\n\n${errorMessage}`;
      }
    },
  });

  // Tool: Index Codebase
  server.addTool({
    name: "index_codebase",
    description: "Index a codebase directory for semantic search. This will scan all supported files, extract code blocks, generate embeddings, and store them in the vector database. Shell command: 'shell_command index <directory>'",
    parameters: indexCodebaseSchema,
    execute: async (args) => {
      const orch = await getOrchestrator(args.directory);
      lastIndexedWorkspace = args.directory;
      return await indexCodebaseTool(args, orch);
    },
  });

  // Tool: Search Code
  server.addTool({
    name: "search_code",
    description: "Perform semantic search on the indexed codebase. Use natural language queries to find relevant code snippets, functions, classes, or documentation. Shell command: 'shell_command search \"query text\"' or with options: 'shell_command search --max-results 10 --min-score 0.8 \"query text\"'",
    parameters: searchCodeSchema,
    execute: async (args) => {
      if (!lastIndexedWorkspace) {
        return "❌ No codebase has been indexed yet. Please use the `index_codebase` tool first to index a directory.";
      }
      const orch = await getOrchestrator(lastIndexedWorkspace);
      return await searchCodeTool(args, orch);
    },
  });

  // Tool: Get Index Status
  server.addTool({
    name: "get_index_status",
    description: "Check the current status of the code index, including indexing progress, statistics, and system state. Shell command: 'shell_command status'",
    parameters: getIndexStatusSchema,
    execute: async (args) => {
      if (!lastIndexedWorkspace) {
        return "📊 **Code Index Status**\n\n**State:** ⏸️ STANDBY\n**Message:** No codebase has been indexed yet\n\n**Next Steps:**\n- Use the `index_codebase` tool to start indexing a directory\n- Make sure your embedding service and vector database are configured";
      }
      const orch = await getOrchestrator(lastIndexedWorkspace);
      return await getIndexStatusTool(args, orch);
    },
  });

  // Tool: Clear Index
  server.addTool({
    name: "clear_index",
    description: "Clear all indexed data from the vector database and cache. This will reset the system to its initial state. Shell command: 'shell_command clear --confirm true'",
    parameters: clearIndexSchema,
    execute: async (args) => {
      if (!lastIndexedWorkspace) {
        return "ℹ️ No codebase has been indexed yet. Nothing to clear.";
      }
      const orch = await getOrchestrator(lastIndexedWorkspace);
      const result = await clearIndexTool(args, orch);
      
      // Reset the last indexed workspace after clearing
      if (result.includes("✅")) {
        lastIndexedWorkspace = null;
      }
      
      return result;
    },
  });

  // Add a configuration tool to help users verify their setup
  server.addTool({
    name: "verify_configuration",
    description: "Verify that the embedder and vector database are properly configured and accessible. Shell command: 'shell_command verify'",
    parameters: z.object({}),
    execute: async () => {
      try {
        console.log("Verifying configuration...");
        
        // Test embedder configuration
        const embeddingValidation = validateEmbedderConfig();
        if (!embeddingValidation.valid) {
          return `❌ **Embedder Configuration Error**\n\n${embeddingValidation.error}\n\nPlease check your .env file and ensure all required variables are set.`;
        }

        // Test embedder connectivity
        const embedder = EmbedderFactory.createEmbedder();
        const embeddingTest = await embedder.validateConfiguration();
        if (!embeddingTest.valid) {
          return `❌ **Embedder Connection Error**\n\n${embeddingTest.error}\n\nPlease verify your embedder service is running and credentials are correct.`;
        }

        // Test vector store connectivity
        const vectorStoreConfig = getVectorStoreConfig();
        const vectorDimensions = EmbedderFactory.getVectorDimensions();
        const vectorStore = new QdrantVectorStore(
          "/tmp/test",
          vectorStoreConfig.url,
          vectorDimensions,
          vectorStoreConfig.apiKey
        );
        await vectorStore.initialize();

        return `✅ **Configuration Verified Successfully**

**Embedder:** ${embedder.embedderInfo.name}
**Vector Database:** Connected to ${vectorStoreConfig.url}
**Vector Dimensions:** Code: ${vectorDimensions.code}, Text: ${vectorDimensions.text}

Your system is ready for codebase indexing and search!`;
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return `❌ **Configuration Error**\n\n${errorMessage}\n\nPlease check your .env file and ensure all services are running.`;
      }
    },
  });

  return server;
}
